
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;


/**
 * @author yudy
 * Created by 2022/9/10
 */

public class MyLiveTest {

    private static int frameRate = 16;// 录制的帧率
    static Frame imgFrame = null;
    static String url = "rtmp://172.18.110.1/live/livestream2";
    static boolean isStop = false;

    public static void start() throws Exception {
        // 帧记录
        // window 建议使用 FFmpegFrameGrabber("desktop") 进行屏幕捕捉
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("https://rtmp03open.ys7.com:9188/v3/openlive/FM1013328_5_2.flv?expire=1764578788&id=785185403079196672&t=d5480a89ae54fe77754f7a3ad01ee227ab4bc044b56330b0fd4fba9683341171&ev=100");
        grabber.setFormat("flv");
        grabber.setFrameRate(frameRate);// 帧获取间隔
//        System.out.println("原视频帧率:"+ grabber.getFrameRate());
        grabber.setOption("framerate", "25");
        grabber.setOption("draw_mouse", "0");
        // 捕获指定区域，不设置则为全屏
//        grabber.setImageHeight(600);
//        grabber.setImageWidth(800);
        // grabber.setOption("offset_x", "200");
        // grabber.setOption("offset_y", "200");//必须设置了大小才能指定区域起点，参数可参考 FFmpeg 入参
        grabber.start();
        //初始化默认帧,用于锁屏状态下无法或者图形的问题导致异常
//        if (imgFrame == null){
//            InputStream in = this.getClass().getClassLoader().getResourceAsStream("img.jpeg");
//            BufferedImage image = ImageIO.read(in);
//            Java2DFrameConverter java2dConverter = new Java2DFrameConverter();
//            imgFrame = java2dConverter.convert(image);
//        }


        // 直播推流
        //推送固定大小分辨率的图像
        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(
                url,grabber.getImageWidth(),grabber.getImageHeight(),0);
        //推送实际小打分辨率的图像
//        FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(
//                url,
//                grabber.getImageWidth(), grabber.getImageHeight(), 0);
        recorder.setMaxDelay(5000);

        // 用于存储视频 , 调用stop后，需要释放，就会在指定位置输出文件，，这里我保存到D盘
        //FFmpegFrameRecorder recorder = FFmpegFrameRecorder.createDefault(file, grabber.getImageWidth(), grabber.getImageHeight());
        recorder.setInterleaved(true);
        // https://trac.ffmpeg.org/wiki/StreamingGuide
        recorder.setVideoOption("tune", "zerolatency");// 加速  零延迟
        //recorder.setVideoOption("flvflags", "no_duration_filesize");// 加速
        // https://trac.ffmpeg.org/wiki/Encode/H.264
        recorder.setVideoOption("preset", "ultrafast");
        recorder.setFrameRate(frameRate);// 设置帧率，重要！
        // Key frame interval, in our case every 2 seconds -> 30 (fps) * 2 = 60
        recorder.setGopSize(frameRate * 2);
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);// 编码，使用编码能让视频占用内存更小，根据实际自行选择
//        recorder.profile(AVCodecContext.FF_PROFILE_H264_CONSTRAINED_BASELINE);
        // https://trac.ffmpeg.org/wiki/Encode/H.264
        recorder.setVideoOption("crf", "28");
        // 2000 kb/s  720P
        recorder.setVideoBitrate(1000000);
        recorder.setFormat("flv");


        recorder.start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean isStop = false;
                try {
                    // 获取屏幕捕捉的一帧
                    // 屏幕录制，由于已经对音频进行了记录，需要对记录时间进行调整即可
                    // 即上面调用了 recorder.recordSamples 需要重新分配时间，否则视频输出时长等于实际 的2倍
//                    while ((frame = grabber.grab()) != null) {
                    int index =0;
                    while (!isStop) {
                        Frame frame = grabber.grabFrame();
                        if (frame != null) {
                            if ( index % frameRate == 0){
                                Thread.sleep(1000);
                            }
                            recorder.record(frame);
                        }
                        index++;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    isStop = true;
                }

                try {
                    // 停止
                    recorder.stop();
                    grabber.stop();
                    // 释放内存，我们都知道c/c++需要手动释放资源
                    recorder.release();
                    grabber.release();
                    System.out.println("停止直播完成");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }).start();
    }

    public static void main(String[] args) throws Exception {
        start();
    }

}

